import { EventClass } from "@lib/alen-helper/node/baseClass";
import { Application } from "../application/application";
import { BrowserWindow, ipcMain } from 'electron';
import { Subject, Subscription, concatMap, fromEvent, mergeMap } from "rxjs";
import * as Path from "path";


export class WindowOperator extends EventClass<Runtime.Operator.EventData<Runtime.OperatorCls.Window.Events>> implements Runtime.OperatorCls.Window {

    readonly type = 'window';

    constructor(
        public readonly id: string,
        public readonly app: Application,
        options: Partial<Runtime.OperatorCls.Window.Options>,
        BaseOptions?: Partial<EventClass.BaseOptions>
    ) {
        super('WindowOperator', BaseOptions);
        this._options = Object.assign(this._options, options);
    }

    private _options: Runtime.OperatorCls.Window.Options = {
        title: '',
        file: '',
        show: true,
        width: 0,
        height: 0,
    };

    get options() {
        return this._options;
    }

    private _src: BrowserWindow | null = null;
    private _subs: Subscription | null = null;


    private _unSub() {
        if (this._subs) this._subs.unsubscribe();
        this._subs = null;
    }

    private _sub() {
        if (!this._src) return;
        this._subs = fromEvent(this._src, 'closed', e => e as null)
            .pipe(concatMap(e => this.triggerEventEnd('destroy', null)))
            .subscribe(e => {
                this._destroy();
                this._src = null;
            });
        this._subs.add(
            fromEvent(this._src, 'close', e => e as Electron.Event)
                .pipe(mergeMap(e => {
                    e.preventDefault();
                    return this.triggerEventEnd('close', {
                        preventClose: false,
                    })
                }))
                .subscribe(e => {
                    if (e.preventClose) return;
                    this.destroy();
                })
        );
        this._subs.add(
            fromEvent(this._src, 'ready-to-show', e => e as null)
                .subscribe(e => {
                    if (!this._src) return;
                    this.triggerEvent('ready', null);
                })
        );
        this._subs.add(
            fromEvent(this._src, 'show', e => e as null)
                .subscribe(e => {
                    this.triggerEvent('show', null);
                })
        );
        this._subs.add(
            fromEvent(this._src, 'hide', e => e as null)
                .subscribe(e => {
                    this.triggerEvent('hide', null);
                })
        );
    }

    start() {
        if (this._src) return true;
        this._src = new BrowserWindow({
            width: this.options.width,
            height: this._options.height,
            show: this._options.show,
            title: this.options.title,
            webPreferences: {
                preload: Path.join(__dirname, 'preload.bundle.js'),
                nodeIntegration: true,
                devTools: true,
                contextIsolation: false,
                sandbox: false,
                additionalArguments: [`--channel=${this.app.ipcChannel}`, `--id=${this.id}`],
            }
        });
        this._sub();
        const filePath = Path.isAbsolute(this.options.file) ? this.options.file : Path.join(this.app.options.cwd, this.options.file);
        this._src.loadFile(filePath);
        this._src.webContents.openDevTools();
        this.triggerEvent('start', null);
        return true;
    }

    show() {
        if (!this._src) return false;
        this._src.show();
        return true;
    }

    hide() {
        if (!this._src) return false;
        this._src.hide();
        return true;
    }

    close() {
        if (!this._src) return false;
        this._src.close();
        //this.triggerEvent('close', {preventClose: false,});
        return true;
    }

    private _destroy() {
        this._unSub();
        this.destroyEvent();
    }

    destroy() {
        if (this._src) {
            this._src.destroy();
            this._src = null;
        }
        return true;
    }
}